package main

import (
	"commons/stores/redis"
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/emicklei/go-restful/log"
)

var (
	redisHandler *redis.Redis
)

const (
	FriendTransactionKey = "friend"
	maxTimeStamp         = 2000000000000
)

type (
	FriendTransaction struct {
		CurrentStep           string
		CurrentSetting        string
		ChatId                int64
		Username              string
		Gender                int
		Introduce             string
		City                  string
		Avatar                string
		ExpectGender          int
		SetTimestamp          int64
		RecommendChatIdRecord map[string]int64
	}
)

func initRedis(redisAddress, redisType string) {
	redisHandler = redis.NewRedis(redisAddress, redisType)
}

func getFriendTransaction(chatId int64) (FriendTransaction, error) {
	var ft FriendTransaction
	ft.RecommendChatIdRecord = map[string]int64{
		fmt.Sprintf("start:%v", Male):            int64(0),
		fmt.Sprintf("end:%v", Male):              int64(0),
		fmt.Sprintf("current:%v", Male):          int64(0),
		fmt.Sprintf("start:%v", Female):          int64(0),
		fmt.Sprintf("end:%v", Female):            int64(0),
		fmt.Sprintf("current:%v", Female):        int64(0),
		fmt.Sprintf("start:%v", MaleAndFemale):   int64(0),
		fmt.Sprintf("end:%v", MaleAndFemale):     int64(0),
		fmt.Sprintf("current:%v", MaleAndFemale): int64(0),
	}
	jsonStr, err := redisHandler.GetHashField(FriendTransactionKey, fmt.Sprint(chatId))
	if err != nil || jsonStr == "" {
		return ft, err
	}

	err = json.Unmarshal([]byte(jsonStr), &ft)
	if err != nil {
		return ft, err
	}
	return ft, nil
}

func delFriendTransaction(chatId int64) error {
	_, err := redisHandler.DelHashField(FriendTransactionKey, fmt.Sprint(chatId))
	return err
}

func saveFriendTransaction(ft FriendTransaction) error {
	bytes, err := json.Marshal(ft)
	if err != nil {
		return err
	}
	return redisHandler.SetHashField(FriendTransactionKey, fmt.Sprint(ft.ChatId), string(bytes))
}

func saveRecommendFriends(gender int, chatId, timestamp int64) error {
	var err error
	_, err = redisHandler.Zadd(fmt.Sprintf("friends:%v", gender), fmt.Sprint(timestamp), fmt.Sprint(chatId))
	_, err = redisHandler.Zadd(fmt.Sprintf("friends:%v", MaleAndFemale), fmt.Sprint(timestamp), fmt.Sprint(chatId))
	return err
}

func delRecommendFriends(gender int, chatId int64) error {
	var err error
	if _, err = redisHandler.Zrem(fmt.Sprintf("friends:%v", gender), fmt.Sprint(chatId)); err != nil {
		return err
	}
	if _, err = redisHandler.Zrem(fmt.Sprintf("friends:%v", MaleAndFemale), fmt.Sprint(chatId)); err != nil {
		return err
	}
	return nil
}

func getRecommendFriend(friend *FriendTransaction) (FriendTransaction, error) {

	var start int64
	if friend.RecommendChatIdRecord[fmt.Sprintf("current:%v", friend.ExpectGender)] == 0 {
		start = int64(maxTimeStamp)
	} else {
		start = friend.RecommendChatIdRecord[fmt.Sprintf("current:%v", friend.ExpectGender)] - 1
	}
	end := friend.RecommendChatIdRecord[fmt.Sprintf("end:%v", friend.ExpectGender)]

	lastFriendTimestamp := getLastFriendTimestamp(friend.ExpectGender, start, end)

	var ft FriendTransaction
	pair, err := redisHandler.ZRevrangeWithScoresAndLimit(fmt.Sprintf("friends:%v", friend.ExpectGender), start, (end + 1), 0, 1)
	if err != nil || len(pair) != 1 {
		return ft, err
	}

	chatId, _ := strconv.ParseInt(pair[0].Key, 10, 64)
	chatIdStmp, _ := strconv.ParseInt(pair[0].Value, 10, 64)

	if start == maxTimeStamp && friend.RecommendChatIdRecord[fmt.Sprintf("end:%v", friend.ExpectGender)] == 0 {
		friend.RecommendChatIdRecord[fmt.Sprintf("start:%v", friend.ExpectGender)] = chatIdStmp
		friend.RecommendChatIdRecord[fmt.Sprintf("end:%v", friend.ExpectGender)] = getFirstFriendTimestamp(friend.ExpectGender) - 1
	} else if start == (maxTimeStamp - 1) {
		friend.RecommendChatIdRecord[fmt.Sprintf("start:%v", friend.ExpectGender)] = chatIdStmp
	}

	if chatIdStmp == lastFriendTimestamp {
		if friend.RecommendChatIdRecord[fmt.Sprintf("start:%v", friend.ExpectGender)] != 0 {
			friend.RecommendChatIdRecord[fmt.Sprintf("end:%v", friend.ExpectGender)] = friend.RecommendChatIdRecord[fmt.Sprintf("start:%v", friend.ExpectGender)]
		}
		friend.RecommendChatIdRecord[fmt.Sprintf("current:%v", friend.ExpectGender)] = maxTimeStamp
	} else {
		friend.RecommendChatIdRecord[fmt.Sprintf("current:%v", friend.ExpectGender)] = chatIdStmp
	}

	if chatId == friend.ChatId {
		return getRecommendFriend(friend)
	}
	return getFriendTransaction(chatId)
}

func getLastFriendTimestamp(expectGender int, start, end int64) (t int64) {
	pair, err := redisHandler.ZrangeWithScoresAndLmit(fmt.Sprintf("friends:%v", expectGender), end+1, start, 0, 1)
	if err != nil {
		log.Printf("Fail on getLastFriendTimestamp, err :%v\n", err)
		return
	}
	if len(pair) == 0 {
		return
	}
	t, _ = strconv.ParseInt(pair[0].Value, 10, 64)
	return
}

func getFirstFriendTimestamp(expectGender int) (chatIdStmp int64) {
	pair, err := redisHandler.ZrangeWithScoresAndLmit(fmt.Sprintf("friends:%v", expectGender), "-inf", "+inf", 0, 1)
	if err != nil {
		return int64(0)
	}
	if len(pair) == 0 {
		return
	}
	chatIdStmp, _ = strconv.ParseInt(pair[0].Value, 10, 64)
	return
}
